import notifier, { NotificationMetadata } from 'node-notifier'
import chalk from 'chalk'
import { builtIn, builtInRunPrefix } from '../config'
import path from 'path'
import { exec } from 'child_process'

/**
 * 系统提示框
 * @param title - 标题
 * @param message - 内容
 * @param fn - 点击回调
 */
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function notice(title: string, message: string, context: any) {
  const OPEN = 'open Directory'
  const actions = []
  if ([1, 2, 3, '1', '2', '3'].includes(context.model)) actions.push(OPEN)
  notifier.notify(
    {
      title,
      message,
      icon: path.join(__dirname, '../../erg.gif'),
      actions
    },
    (err: Error | null, response: string, options?: NotificationMetadata) => {
      if (err) throw err
      switch (response) {
        case OPEN.toLowerCase():
          exec(
              `explorer.exe /select,"${path.resolve(
                context.runPath,
                'dist.zip'
              )}"`
          )
          break
      }
    }
  )
}

/**
 * 返回检测类型
 * @export
 * @param {unknown} value - 要被检测类型的数据
 * @param {string} type - 匹配的类型 'String|Number|Boolean|Null|Undefined...'
 * @returns {(boolean | string)}
 */
export function toType(value: unknown, type?: string): boolean | string {
  if (type) return Object.prototype.toString.call(value).slice(8, -1) === type
  return Object.prototype.toString.call(value).slice(8, -1)
}

/**
 * 简化Promise流程
 * @export
 * @template T
 * @param {(Promise<T> | Promise<T>[])} method - 异步方法
 * @param {{ before: () => void, after: () => void }} [cb] - 回调方法 { before, after }
 * @returns {Promise<any>}
 */
export function to<T>(method: Promise<T> | Promise<T>[], cb?: { before: () => void, after: () => void }): Promise<any> {
  method = Array.isArray(method) ? method : [method]
  if (typeof cb === 'object' && cb.before) cb.before()
  return Promise.all(method)
    .then((res) => [null, ...res])
    .catch((err) => [err])
    .finally(() => {
      if (typeof cb === 'object' && cb.after) cb.after()
    })
}

export function defaultLog(log: string): undefined {
  return console.log(chalk.blue(`---------------- ${log} ----------------`)) as undefined
}

export function errorLog(log: string): undefined {
  return console.log(chalk.red(`---------------- ${log} ----------------`)) as undefined
}

export function successLog(log: string): undefined {
  return console.log(chalk.green(`---------------- ${log} ----------------`)) as undefined
}

export function timeLog(log: string): undefined {
  return console.time(chalk.yellow(`>>>>>${log}<<<<<`)) as undefined
}

export function timeEndLog(log: string): undefined {
  return console.timeEnd(chalk.yellow(`>>>>>${log}<<<<<`)) as undefined
}

export function isValidKey(key: string | number | symbol, object: Record<string, unknown>): key is keyof typeof object {
  return key in object
}

/**
 * 生成指令函数
 * @export
 * @template T
 * @param {T} self
 * @param {string} script - 指令
 * @param {string} [label]
 * @returns {({ fn: () => Promise<any>, label: string } | undefined)}
 */
export function geoBuiltIn<T>(self: T, script: string, label?: string): { fn: () => Promise<any>, label: string } | undefined {
  if (!script) return
  if (script.indexOf(builtInRunPrefix) === 0) { // 模式4 使用内置指令
    const model = Number(script.slice(builtInRunPrefix.length))
    if (Number.isNaN(model) || !isValidKey(model, builtIn)) return
    const cur: { run: string, label: string } = builtIn[model]
    return { fn: self[cur.run], label: cur.label }
  } else {
    if (self[script]) { // 选择模式3
      return { fn: self[script], label: label || '' }
    }

    // 模式4
    const runCommand = '_runCommand'
    return { fn: () => self[runCommand](script), label: label || script }
  }
}
